using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
using System.Xml.Linq;
using MySql.Data.MySqlClient;
namespace ServerCore.Helper
{

    public class MysqlDataReaderHelper
    {
        public static Dictionary<string, object> readerToObjDic = new Dictionary<string, object>();

        public static List<T> ConvertReader<T>(MySqlDataReader reader) where T : new()
        {
            List<T> result = new List<T>();
            Func<MySqlDataReader, T> convertFunc = createConvertFunc<T>();
            if(reader.HasRows)
            {
                while (reader.Read())
                {
                    try{
                        result.Add(convertFunc(reader));
                    }
                    catch(Exception e)
                    {
                        Console.Write(e.Message);
                        throw new ArgumentException("模型里的字段数据库里没返回");
                    }
                    
                }
            }
            return result;
        }
    
        public static Func<MySqlDataReader, T> createConvertFunc<T>() where T : new()
        {
            string key = typeof(T).FullName;
            if (!readerToObjDic.ContainsKey(key))
            {
                List<Expression> expressions = new List<Expression>();
                var resultType = typeof(T);
                var paraType = typeof(MySqlDataReader);
                var para = Expression.Parameter(paraType, "reader");
                var properties = resultType.GetProperties();
                var returnLabel = Expression.Label(resultType);
                var result = Expression.Variable(resultType, "result");

                BinaryExpression setResult = Expression.Assign(result, Expression.New(resultType));
                expressions.Add(setResult);
                Expression getValue = null;
                foreach (var property in properties)
                {
                    // model属性
                    var propertyEx = Expression.Property(result, property);
                    if (property.PropertyType == typeof(string))
                    {
                        getValue = Expression.Call(para, "GetString", null, new Expression[] { Expression.Constant(property.Name) });
                    }
                    else if (property.PropertyType == typeof(Int64))
                    {
                        getValue = Expression.Call(para, "GetInt64", null, new Expression[] { Expression.Constant(property.Name) });
                    }
                    else if (property.PropertyType == typeof(Int32))
                    {
                        getValue = Expression.Call(para, "GetInt32", null, new Expression[] { Expression.Constant(property.Name) });
                    }
                    else if (property.PropertyType == typeof(bool))
                    {
                        getValue = Expression.Call(para, "GetBoolean", null, new Expression[] { Expression.Constant(property.Name) });
                    }
                    else if (property.PropertyType == typeof(float))
                    {
                        getValue = Expression.Call(para, "GetFloat", null, new Expression[] { Expression.Constant(property.Name) });
                    }
                    else if (property.PropertyType == typeof(double))
                    {
                        getValue = Expression.Call(para, "GetDouble", null, new Expression[] { Expression.Constant(property.Name) });
                    }
                    else {
                        getValue = Expression.Constant(null);
                    }
                    // 将值设置到对应的属性
                    var setProperty = Expression.Assign(propertyEx, getValue);
                    var index = Expression.Call(para,"GetOrdinal",null,new Expression[] { Expression.Constant(property.Name)} );
                    var checkNull = Expression.IfThen(Expression.Equal(Expression.Call(para,"IsDBNull",null,new Expression[] { index}),Expression.Constant(false)),setProperty);
                    var trycatch = Expression.TryCatch(Expression.Block(checkNull, Expression.Constant(0)), Expression.Catch(typeof(DivideByZeroException), Expression.Constant(0)));
                    expressions.Add(trycatch);


                }

                GotoExpression ge = Expression.Return(returnLabel, result, resultType);
                var lbl = Expression.Label(returnLabel, Expression.New(resultType));
                expressions.Add(ge);
                expressions.Add(lbl);

                BlockExpression blocks = Expression.Block(new ParameterExpression[] { result }, expressions);
                Expression<Func<MySqlDataReader, T>> func = Expression.Lambda<Func<MySqlDataReader, T>>(blocks, new ParameterExpression[] { para });
                readerToObjDic[key] = func.Compile();
                return readerToObjDic[key] as Func<MySqlDataReader, T>;

            }
            else
            {
                return readerToObjDic[key] as Func<MySqlDataReader, T>;
            }
        }

    
    }
}
